package com.gomro.galaxy.foundation.bi.engine.analysis;

import cn.gomro.cloud.core.common.utils.DateUtils;
import cn.gomro.cloud.core.common.utils.EncryptUtils;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gomro.galaxy.core.batch.ElasticSearchClzItemReader;
import com.gomro.galaxy.core.batch.ElasticSearchClzItemWriter;
import com.gomro.galaxy.core.commons.elastic.ElasticSearchRest;
import com.gomro.galaxy.foundation.bi.domain.Constants;
import com.gomro.galaxy.foundation.bi.domain.enumerater.InquiryGoodsStatus;
import com.gomro.galaxy.foundation.bi.domain.enumerater.QuotationStatusEnum;

import com.gomro.galaxy.foundation.bi.domain.event.VirtualVendorQuotationEvent;
import com.gomro.galaxy.foundation.bi.domain.model.*;
import com.gomro.galaxy.foundation.bi.domain.model.analysis.VirtualVendorQuotationVolume;
import com.gomro.galaxy.foundation.bi.engine.AnalysisLastTime;
import com.gomro.galaxy.foundation.bi.engine.model.AnalysisCache;
import com.gomro.galaxy.foundation.bi.engine.query.*;
import com.gomro.galaxy.foundation.bi.engine.util.BoolQueryBuilders;
import com.gomro.galaxy.foundation.bi.engine.util.EngineUtils;
import com.gomro.galaxy.foundation.bi.exception.BiException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.batch.core.*;
import org.springframework.batch.core.configuration.annotation.JobBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepBuilderFactory;
import org.springframework.batch.core.configuration.annotation.StepScope;
import org.springframework.batch.core.launch.support.RunIdIncrementer;
import org.springframework.batch.item.ItemProcessor;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.cloud.bus.BusProperties;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.lang.NonNull;
import org.springframework.util.CollectionUtils;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import static com.gomro.galaxy.foundation.bi.engine.util.EngineUtils.MAX_BATCH_NUM;

/**
 * 运营工作台 虚拟供应商报价统计
 *
 * @author xue
 * @date 2020/5/27
 */
@Slf4j
@Configuration
public class VirtualVendorQuotationJob {
    private static final String BiAnalysisLastName = Constants.BiDataMartIndexPrefix + AnalysisLastTime.TableName;
    private static final String BiWarehouseOrganizationName = Constants.BiWarehouseIndexPrefix + AcquireOrganization.TableName;
    private static final String BiWarehouseBindingInventedVendorName = Constants.BiWarehouseIndexPrefix + AcquireBindingInventedVendor.TableName;
    private static final String BiWarehouseQuotationGoodsName = Constants.BiWarehouseIndexPrefix + AcquireQuotationGoods.TableName;
    private static final String BiWarehouseInquiryGoodsName = Constants.BiWarehouseIndexPrefix + AcquireInquiryGoods.TableName;
    private static final String BiWarehouseInquiryGoodsClarifyName = Constants.BiWarehouseIndexPrefix + AcquireInquiryGoodsClarify.TableName;

    private static final String BiWarehouseInquiryName = Constants.BiWarehouseIndexPrefix + AcquireInquiry.TableName;
    private static final String BiWarehouseMemberName = Constants.BiWarehouseIndexPrefix + AcquireMember.TableName;
    private static final String BiDataMartName = Constants.BiDataMartIndexPrefix + VirtualVendorQuotationVolume.TableName;
    private static final String JobName = Constants.JobBeanNamePrefix + VirtualVendorQuotationVolume.TableName;

    //第一次读写执行 查未报价询价
    private static final String FirstReaderName = Constants.ReaderBeanNamePrefix + VirtualVendorQuotationVolume.TableName + "_first";
    private static final String FirstProcessName = Constants.ProcessBeanNamePrefix + VirtualVendorQuotationVolume.TableName + "_first";
    private static final String FirstWriterName = Constants.WriterBeanNamePrefix + VirtualVendorQuotationVolume.TableName + "_first";


    //第二次读写执行 查报价询价，这时间澄清记录，产品经理，报价信息，供应商组织信息都能查出来
    private static final String SecondReaderName = Constants.ReaderBeanNamePrefix + VirtualVendorQuotationVolume.TableName + "_second";
    private static final String SecondProcessName = Constants.ProcessBeanNamePrefix + VirtualVendorQuotationVolume.TableName + "_second";
    private static final String SecondWriterName = Constants.WriterBeanNamePrefix + VirtualVendorQuotationVolume.TableName + "_second";

    //执行步骤
    private static final String FirstStepName = Constants.StepBeanNamePrefix + VirtualVendorQuotationVolume.TableName + "_first";
    private static final String SecondStepName = Constants.StepBeanNamePrefix + VirtualVendorQuotationVolume.TableName + "_second";

    private ApplicationEventPublisher applicationEventPublisher;
    private BusProperties busProperties;
    private JobBuilderFactory jobBuilderFactory;
    private StepBuilderFactory stepBuilderFactory;
    private ElasticSearchRest rest;
    private RestHighLevelClient client;
    private ObjectMapper mapper;
    private AnalysisCache<VirtualVendorQuotationVolume> cache = new AnalysisCache<>();

    public VirtualVendorQuotationJob(ApplicationEventPublisher applicationEventPublisher, BusProperties busProperties, JobBuilderFactory jobBuilderFactory, StepBuilderFactory stepBuilderFactory, RestHighLevelClient client, ObjectMapper mapper) {
        this.applicationEventPublisher = applicationEventPublisher;
        this.busProperties = busProperties;
        this.jobBuilderFactory = jobBuilderFactory;
        this.stepBuilderFactory = stepBuilderFactory;
        this.client = client;
        this.mapper = mapper;
        this.rest = new ElasticSearchRest(client, mapper);
    }

    private JobExecutionListener jobExecutionListener = new JobExecutionListener() {

        @Override
        public void beforeJob(@NonNull JobExecution jobExecution) {

            ElasticSearchRest rest = new ElasticSearchRest(client, mapper);

            // 初始化数据索引
            if (!rest.indexExists(BiDataMartName)) {

                rest.indexCreate(BiDataMartName);
                rest.indexMappingPut(BiDataMartName, "analysis/" + BiDataMartName + ".json", true);
                rest.indexFlush(BiDataMartName, null, null);
            }

            // 初始化最后更新时间索引
            if (!rest.indexExists(BiAnalysisLastName)) {

                rest.indexCreate(BiAnalysisLastName);
                rest.indexMappingPut(BiAnalysisLastName, "analysis/" + BiAnalysisLastName + ".json", true);
                rest.indexFlush(BiAnalysisLastName, null, null);
            }
        }

        @Override
        public void afterJob(@NonNull JobExecution jobExecution) {
            log.warn("[BiEngineAnalysis-VirtualVendorQuotationJob] last time ---> {}", DateUtils.dateToStr(cache.getLast()));
            if (Objects.nonNull(cache.getCache())) {
                log.warn("[BiEngineAnalysis-VirtualVendorQuotationJob] cache size -> {}", cache.getCache().size());
                cache.getCache().clear();
            }
            // 回写最后更新时间
            if (jobExecution.getStatus() == BatchStatus.COMPLETED) {
                rest.documentCreate(BiAnalysisLastName, BiDataMartName, AnalysisLastTime.builder().id(BiDataMartName).last(cache.getLast()).build());
                applicationEventPublisher.publishEvent(new VirtualVendorQuotationEvent(cache.getLast()));
            }
        }
    };


    /**
     * 逻辑 第一个step查询的是所有没有报价的询价商品信息，
     * 查询条件 未参与0，未报价0
     * 第二个step 是查询报价，此部分为有报价的询价，询价信息，澄清记录等都会查询出来
     * 然后两个数据整合
     *
     * @param firstStep
     * @param secondStep
     * @return
     */
    @Bean(JobName)
    public Job job(@Qualifier(FirstStepName) Step firstStep, @Qualifier(SecondStepName) Step secondStep) {

        return jobBuilderFactory.get(JobName)
                .incrementer(new RunIdIncrementer())
                .start(firstStep)
                .next(secondStep)
                .listener(jobExecutionListener)
                .build();
    }

    @Bean(FirstStepName)
    public Step firstStep() {

        return stepBuilderFactory.get(FirstStepName)
                .<AcquireInquiryGoods, VirtualVendorQuotationVolume>chunk(MAX_BATCH_NUM)
                .reader(firstReader())
                .processor(firstProcessor())
                .writer(firstWriter())
                .build();
    }

    @Bean(SecondStepName)
    public Step secondStep() {

        return stepBuilderFactory.get(SecondStepName)
                .<AcquireQuotationGoods, VirtualVendorQuotationVolume>chunk(MAX_BATCH_NUM)
                .reader(secondReader())
                .processor(secondProcessor())
                .writer(secondWriter())
                .build();
    }

    /**
     * 先读出来未参与，未报价的询价信息
     *
     * @return
     */
    @Bean(FirstReaderName)
    @StepScope
    public ElasticSearchClzItemReader<AcquireInquiryGoods> firstReader() {
        AnalysisLastTime analysisLastTime = rest.documentGet(BiAnalysisLastName, BiDataMartName, AnalysisLastTime.class);
        Date start;
        if (analysisLastTime != null && analysisLastTime.getLast() != null) {
            start = analysisLastTime.getLast();
        } else {
            ElasticSearchRest.SearchResultClz<AcquireInquiryGoods> data = rest.searchAsClz(BiWarehouseInquiryGoodsName, ElasticSearchRest.Page.of(1, 1), null, Collections.singleton(SortBuilders.fieldSort("time").order(SortOrder.ASC)), null, AcquireInquiryGoods.class);
            if (Objects.isNull(data) || CollectionUtils.isEmpty(data.getData())) {
                throw new BiException("analysisLastTime init error");
            }
            start = Date.from(data.getData().get(0).getTime().atZone(ZoneId.systemDefault()).toInstant());
        }
        cache.setLast(start);
        Date endDate = EngineUtils.getEndDate(start, (date, date2) -> rest.searchCount(BiWarehouseInquiryGoodsName,
                BoolQueryBuilders.inquiryGoods(InquiryGoodsQuery.builder().start(date).end(date2).quoteCount(0).partakeCount(0).del(false).build())));
        if (Objects.nonNull(endDate)) {
            cache.setLast(endDate);
        } else {
            endDate = new Date();
            cache.setLast(endDate);
        }
        //初始化缓存, 不能并行任务
        if (Objects.isNull(cache.getCache())) {
            cache.setCache(new HashMap<>());
        }

        BoolQueryBuilder boolQuery = BoolQueryBuilders.inquiryGoods(InquiryGoodsQuery.builder().quoteCount(0).partakeCount(0).start(start).end(endDate).del(false).build());
        long count = rest.searchCount(BiWarehouseInquiryGoodsName, boolQuery);
        log.warn("[BiEngineAnalysis-VirtualVendorQuotationJob] 查询日期 -> {} count -> {}", DateUtils.dateToStr(cache.getLast(), DateUtils.FORMAT_PATTERN_DATE), count);

        ElasticSearchClzItemReader<AcquireInquiryGoods> reader = new ElasticSearchClzItemReader<>(client, mapper, BiWarehouseInquiryGoodsName,
                MAX_BATCH_NUM, boolQuery, Collections.singleton(SortBuilders.fieldSort("id").order(SortOrder.ASC)), AcquireInquiryGoods.class);
        reader.setName(FirstReaderName);

        return reader;
    }

    /**
     * 第一次执行 只存储未被参与的询价信息，
     * 报价信息都是空的，澄清记录等
     *
     * @return
     */
    @Bean(FirstProcessName)
    public ItemProcessor<AcquireInquiryGoods, VirtualVendorQuotationVolume> firstProcessor() {
        return acquireInquiryGoods -> {

            LocalDateTime inquiryTime = acquireInquiryGoods.getTime();
            LocalDate localDate = inquiryTime.toLocalDate();
            String id = EncryptUtils.MD5_32(localDate.toString() + acquireInquiryGoods.getId());
            String inquiryGoodsStatus = Objects.requireNonNull(InquiryGoodsStatus.get(acquireInquiryGoods.getStatus())).des;

            VirtualVendorQuotationVolume virtualVendorQuotationVolumeBuild = VirtualVendorQuotationVolume.builder()
                    .id(id)
                    .inquiryTime(inquiryTime)
                    .inquiryId(acquireInquiryGoods.getInquiryId())
                    .inquiryGoodsId(acquireInquiryGoods.getId())
                    .inquiryGoodsStatus(inquiryGoodsStatus)
                    .partakeCount(acquireInquiryGoods.getPartakeCount())
                    .quoteCount(acquireInquiryGoods.getQuoteCount())
                    .name(acquireInquiryGoods.getName())
                    .brand(acquireInquiryGoods.getBrand())
                    .model(acquireInquiryGoods.getModel())
                    .spec(acquireInquiryGoods.getSpec())
                    .unit(acquireInquiryGoods.getUnit())
                    .num(acquireInquiryGoods.getNum())
                    .quotationGoodsId(null)
                    .amount(null)
                    .price(null)
                    .address(null)
                    .delivery(null)
                    .productManager(null)
                    .memo(null)
                    .vendorName(null)
                    .clarifyTips(null)
                    .quotationTime(null)
                    .quotationStatus(null)
                    .isVirtualVendor(false)
                    .build();
            //此部分查询询价单信息，构建对象返回字段
            AcquireInquiry inquiry = rest.documentGet(BiWarehouseInquiryName, acquireInquiryGoods.getInquiryId().toString(), AcquireInquiry.class);
            if (Objects.isNull(inquiry)) {
                log.warn("[BiEngineAnalysis-VirtualVendorQuotationJob] 询价单" + acquireInquiryGoods.getInquiryId() + "未找到!");
                return virtualVendorQuotationVolumeBuild;
            }
            virtualVendorQuotationVolumeBuild.setInquiryOrganizationName(StringUtils.trim(inquiry.getOrganizationCompanyName()));

            return virtualVendorQuotationVolumeBuild;
        };
    }

    /**
     * 未报价询价写入最终前台需要的数据实体
     *
     * @return
     */
    @Bean(FirstWriterName)
    public ElasticSearchClzItemWriter<VirtualVendorQuotationVolume> firstWriter() {
        return new ElasticSearchClzItemWriter<>(client, mapper, BiDataMartName);
    }


    /**
     * 第二次查报价 此部分查询有报价的询价，
     *
     * @return
     */
    @Bean(SecondReaderName)
    @StepScope
    public ElasticSearchClzItemReader<AcquireQuotationGoods> secondReader() {
        AnalysisLastTime analysisLastTime = rest.documentGet(BiAnalysisLastName, BiDataMartName, AnalysisLastTime.class);
        Date start;
        if (analysisLastTime != null && analysisLastTime.getLast() != null) {
            start = analysisLastTime.getLast();
        } else {
            ElasticSearchRest.SearchResultClz<AcquireQuotationGoods> data = rest.searchAsClz(BiWarehouseQuotationGoodsName, ElasticSearchRest.Page.of(1, 1), null, Collections.singleton(SortBuilders.fieldSort("time").order(SortOrder.ASC)), null, AcquireQuotationGoods.class);
            if (Objects.isNull(data) || CollectionUtils.isEmpty(data.getData())) {
                throw new BiException("analysisLastTime init error");
            }
            start = Date.from(data.getData().get(0).getTime().atZone(ZoneId.systemDefault()).toInstant());
        }
        cache.setLast(start);
        Date endDate = EngineUtils.getEndDate(start, (date, date2) -> rest.searchCount(BiWarehouseQuotationGoodsName,
                BoolQueryBuilders.quotationGoods(QuotationGoodsQuery.builder().start(date).end(date2).del(false).build())));
        if (Objects.nonNull(endDate)) {
            cache.setLast(endDate);
        } else {
            endDate = new Date();
            cache.setLast(endDate);
        }
        //初始化缓存, 不能并行任务
        if (Objects.isNull(cache.getCache())) {
            cache.setCache(new HashMap<>());
        }

        BoolQueryBuilder boolQuery = BoolQueryBuilders.quotationGoods(QuotationGoodsQuery.builder().start(start).end(endDate).del(false).build());
        long count = rest.searchCount(BiWarehouseQuotationGoodsName, boolQuery);
        log.warn("[BiEngineAnalysis-VirtualVendorQuotationJob] 查询日期 -> {} count -> {}", DateUtils.dateToStr(cache.getLast(), DateUtils.FORMAT_PATTERN_DATE), count);

        ElasticSearchClzItemReader<AcquireQuotationGoods> reader = new ElasticSearchClzItemReader<>(client, mapper, BiWarehouseQuotationGoodsName,
                MAX_BATCH_NUM, boolQuery, Collections.singleton(SortBuilders.fieldSort("id").order(SortOrder.ASC)), AcquireQuotationGoods.class);
        reader.setName(SecondReaderName);

        return reader;
    }


    /**
     * 第二次执行 只查询报价，此部分是有报价的询价，组织信息，对应的产品经理
     *
     * @return
     */
    @Bean(SecondProcessName)
    public ItemProcessor<AcquireQuotationGoods, VirtualVendorQuotationVolume> secondProcessor() {
        return acquireQuotationGoods -> {

            LocalDateTime quotationGoodsTime = acquireQuotationGoods.getTime();
            LocalDate localDate = quotationGoodsTime.toLocalDate();
            String id = EncryptUtils.MD5_32(localDate.toString() + acquireQuotationGoods.getVendorOrganizationName() + acquireQuotationGoods.getId());
            QuotationStatusEnum quotationStatusEnum = QuotationStatusEnum.get(acquireQuotationGoods.getStatus());
            String quotationStatus = QuotationStatusEnum.QUOTATION_0_NEW.equals(quotationStatusEnum) ? "已参与或已参与未提交" : quotationStatusEnum.des;

            //设置报价部分的信息
            VirtualVendorQuotationVolume virtualVendorQuotationVolumeBuild = VirtualVendorQuotationVolume.builder()
                    .id(id)
                    .quotationGoodsId(acquireQuotationGoods.getId())
                    .name(acquireQuotationGoods.getName())
                    .brand(acquireQuotationGoods.getBrand())
                    .model(acquireQuotationGoods.getModel())
                    .unit(acquireQuotationGoods.getUnit())
                    .num(acquireQuotationGoods.getNum())
                    .amount(acquireQuotationGoods.getAmount())
                    .price(acquireQuotationGoods.getPrice())
                    .address(acquireQuotationGoods.getAddress())
                    .delivery(acquireQuotationGoods.getDelivery())
                    .memo(acquireQuotationGoods.getDescription())
                    .vendorName(acquireQuotationGoods.getVendorOrganizationName())
                    .quotationTime(quotationGoodsTime)
                    .quotationStatus(quotationStatus)
                    .build();


            //此部分查询询价单信息，构建对象返回字段
            AcquireInquiryGoods inquiryGoods = rest.documentGet(BiWarehouseInquiryGoodsName, acquireQuotationGoods.getInquiryGoodsId().toString(), AcquireInquiryGoods.class);
            if (Objects.isNull(inquiryGoods)) {
                log.warn("[BiEngineAnalysis-VirtualVendorQuotationJob] 询价商品单" + acquireQuotationGoods.getInquiryGoodsId() + "未找到!");
                return virtualVendorQuotationVolumeBuild;
            }
            //设置询价商品信息
            virtualVendorQuotationVolumeBuild.setInquiryGoodsStatus(Objects.requireNonNull(InquiryGoodsStatus.get(inquiryGoods.getStatus())).des)
                    .setPartakeCount(inquiryGoods.getPartakeCount())
                    .setInquiryGoodsId(inquiryGoods.getId())
                    .setQuoteCount(inquiryGoods.getQuoteCount());


            //查询澄清记录
            BoolQueryBuilder inquiryGoodsClarifyQuery = BoolQueryBuilders.inquiryGoodsClarify(InquiryGoodsClarifyQuery.builder()
                    .del(false)
                    .vendorId(acquireQuotationGoods.getVendorOrganizationId())
                    .InquiryGoodsId(acquireQuotationGoods.getInquiryGoodsId()).build());
            long inquiryGoodsClarifyCount = rest.searchCount(BiWarehouseInquiryGoodsClarifyName, inquiryGoodsClarifyQuery);

            ElasticSearchRest.SearchResultClz<AcquireInquiryGoodsClarify> inquiryGoodsClarify = rest.searchAsClz(BiWarehouseInquiryGoodsClarifyName,
                    ElasticSearchRest.Page.of(1, ((int) (inquiryGoodsClarifyCount))), inquiryGoodsClarifyQuery, null, null, AcquireInquiryGoodsClarify.class);
            String inquiryGoodsClarifyTips = "";
            if (Objects.nonNull(inquiryGoodsClarify) && !CollectionUtils.isEmpty(inquiryGoodsClarify.getData())) {
                //澄清记录直接set
                inquiryGoodsClarifyTips = inquiryGoodsClarify.getData().stream().map(AcquireInquiryGoodsClarify::getClarifyTips).collect(Collectors.joining(","));

            }
            virtualVendorQuotationVolumeBuild.setClarifyTips(inquiryGoodsClarifyTips);


            //此部分查询询价单信息
            AcquireInquiry inquiry = rest.documentGet(BiWarehouseInquiryName, inquiryGoods.getInquiryId().toString(), AcquireInquiry.class);
            if (Objects.isNull(inquiry)) {
                log.warn("[BiEngineAnalysis-VirtualVendorQuotationJob] 询价单" + inquiryGoods.getInquiryId() + "未找到!");
                return virtualVendorQuotationVolumeBuild;
            }
            //set询价单的信息
            virtualVendorQuotationVolumeBuild
                    .setInquiryId(inquiry.getId())
                    .setInquiryOrganizationName(StringUtils.trim(inquiry.getOrganizationCompanyName()))
                    .setInquiryTime(inquiry.getTime());


            //此部分查询组织信息
            AcquireOrganization organization = rest.documentGet(BiWarehouseOrganizationName, acquireQuotationGoods.getVendorOrganizationId().toString(), AcquireOrganization.class);
            if (Objects.isNull(organization)) {
                log.warn("[BiEngineAnalysis-VirtualVendorQuotationJob] 报价组织" + acquireQuotationGoods.getVendorOrganizationId() + "未找到!");
                return virtualVendorQuotationVolumeBuild;
            }
            //set是否是虚拟供应商，用于控制前台显示，真实供应商不显示价格等信息
            virtualVendorQuotationVolumeBuild.setIsVirtualVendor(organization.getVirtual());


            //查询产品经理
            BindingInventedVendorQuery query = BindingInventedVendorQuery.builder().vendorId(acquireQuotationGoods.getVendorOrganizationId()).build();
            BoolQueryBuilder boolQuery = BoolQueryBuilders.bindingInventedVendor(query);
            long count = rest.searchCount(BiWarehouseBindingInventedVendorName, boolQuery);
            String manager = "";

            ElasticSearchRest.SearchResultClz<AcquireBindingInventedVendor> result = rest.searchAsClz(BiWarehouseBindingInventedVendorName,
                    ElasticSearchRest.Page.of(1, ((int) (count))), boolQuery, null, null, AcquireBindingInventedVendor.class);

            if (Objects.nonNull(result) && !CollectionUtils.isEmpty(result.getData())) {
                List<String> ids = result.getData().stream().map(e -> Objects.toString(e.getBinderId())).collect(Collectors.toList());
                Map<String, AcquireMember> map = rest.documentMultiGet(BiWarehouseMemberName, ids, AcquireMember.class);
                if (!CollectionUtils.isEmpty(map)) {
                    manager = map.values().stream().map(AcquireMember::getFullname).collect(Collectors.joining(","));
                }
            }
            //设置产品经理
            virtualVendorQuotationVolumeBuild.setProductManager(manager);

            return virtualVendorQuotationVolumeBuild;
        };
    }

    /**
     * 写入最后的查询实体
     *
     * @return
     */
    @Bean(SecondWriterName)
    public ElasticSearchClzItemWriter<VirtualVendorQuotationVolume> secondWriter() {
        return new ElasticSearchClzItemWriter<>(client, mapper, BiDataMartName);
    }


}
